package com.eshipenet.shipnet.edgeboxrpc.grpc;

import com.eshipenet.shipnet.edgebox.grpc.*;
import com.eshipenet.shipnet.edgeboxrpc.service.EdgeBoxIdGenerator;
import com.eshipenet.shipnet.edgeboxrpc.util.FormatSql;
import com.eshipenet.shipnet.edgeboxrpc.util.GetJObjectUtil;
import com.eshipenet.shipnet.edgeboxrpc.util.PageUtil;
import com.eshipenet.shipnet.edgeboxrpc.util.TimestampToDate;
import com.google.protobuf.Struct;
import com.google.protobuf.util.Timestamps;
import io.grpc.stub.StreamObserver;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.cache.query.FieldsQueryCursor;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.cache.query.SqlQuery;
import org.json4s.JsonAST;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.Option;
import scala.collection.Seq;
import scala.collection.immutable.List;
import squirrel.JSONQuery;
import squirrel.SqlValue;

import javax.cache.Cache;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;


public class EdgeBoxModelRepoGrpcImpl extends EdgeBoxModelRepoGrpc.EdgeBoxModelRepoImplBase {
  private Logger logger = LoggerFactory.getLogger("EdgeBoxModelRepoGrpcImpl");

  private IgniteCache<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel> cache;
  private EdgeBoxIdGenerator                                              idGenerator;

  public EdgeBoxModelRepoGrpcImpl(IgniteCache<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel> cache,
                                  EdgeBoxIdGenerator idGenerator) {
    this.cache = cache;
    this.idGenerator = idGenerator;
  }


  /**
   * 查询列表
   *
   * @param req
   * @param responseObserver
   */
  public void findAll(EdgeBoxModelFindAllRequest req, StreamObserver<EdgeBoxModelFindAllReply> responseObserver) {

    try {
      logger.info("EdgeBoxModelRepoGrpcImpl.findAll.Filter  {}",req.getFilter().toString());
      EdgeBoxModelFindAllReply reply = findAllInner(req);
      responseObserver.onNext(reply);
      responseObserver.onCompleted();

    } catch (Exception e) {

      responseObserver.onError(e);
    }

  }


  /**
   * 创建
   *
   * @param req
   * @param responseObserver
   */
  public void createOne(EdgeBoxModelCreateOneRequest req, StreamObserver<EdgeBoxModelCreateOneReply> responseObserver) {

    try{
      logger.info("EdgeBoxModelRepoGrpcImpl.createOne.data  {}",req.getData());
      EdgeBoxModelCreateOneReply reply = createOneInner(req);
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }catch (Exception e){
      responseObserver.onError(e);
    }
  }


  /**
   * 修改
   *
   * @param req
   * @param responseObserver
   */
  public void updateOne(EdgeBoxModelUpdateOneRequest req, StreamObserver<EdgeBoxModelUpdateOneReply> responseObserver) {

    try{
      logger.info("EdgeBoxModelRepoGrpcImpl.updateOne.data {}",req.getData());
      EdgeBoxModelUpdateOneReply reply = updateOneInner(req);
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }catch (Exception e){
      responseObserver.onError(e);
    }

  }


  /**
   * 删除
   *
   * @param req
   * @param responseObserver
   */
  public void deleteOne(EdgeBoxModelDeleteOneRequest req, StreamObserver<EdgeBoxModelDeleteOneReply> responseObserver) {

    try{
      logger.info("EdgeBoxModelRepoGrpcImpl.deleteOne.Id {}",req.getId());
      EdgeBoxModelDeleteOneReply reply = deleteOneInner(req);
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }catch (Exception e){
      responseObserver.onError(e);
    }
  }


  EdgeBoxModelFindAllReply findAllInner(EdgeBoxModelFindAllRequest req) {

    int limit = req.getFilter().getLimit();
    int offset = req.getFilter().getOffset();

    if (limit == 0) {
      limit = 500;

    }

    //查询条件
    Struct wheres = req.getFilter().getWhere();

    JsonAST.JObject jObject = GetJObjectUtil.getWhere(wheres);

    List<JsonAST.JValue> includes_list = scala.collection.immutable.List.empty();

    JsonAST.JArray jArray = new JsonAST.JArray(includes_list);

    JSONQuery jsonQuery = JSONQuery.apply(new JsonAST.JString("edgeboxmodel"),
                                          Option.apply(jObject),
                                          Option.apply(new JsonAST.JString("*")),
                                          Option.apply(jArray),
                                          Option.apply(null),
                                          Option.apply(null));

    Map<String, Object> map = FormatSql.getFormatSql(jsonQuery);

    String end_sql = map.get("sql").toString();

    SqlQuery<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel> sql =
      new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBoxModel.class, end_sql);
    Seq<SqlValue> sqlValueSeq = (Seq<SqlValue>) map.get("args");
    sql.setArgs(FormatSql.sqlValueToObject(sqlValueSeq));
    logger.info("query EdgeBoxModel list sql  {}",sql);
    QueryCursor cursor = cache.query(sql);

    //生成查询数据数量的sql
    JSONQuery jsonQuery1 = JSONQuery.apply(new JsonAST.JString("edgeboxmodel"),
                                           Option.apply(jObject),
                                           Option.apply(new JsonAST.JString("count(id) as count")),
                                           Option.apply(jArray),
                                           Option.apply(null),
                                           Option.apply(null));

    Map<String, Object> count_sql = FormatSql.getFormatSql(jsonQuery1);

    String end_query = count_sql.get("sql").toString();

    SqlFieldsQuery sqlFieldsQuery = new SqlFieldsQuery(end_query);

    Seq<SqlValue> sqlValueSeq1 = (Seq<SqlValue>) count_sql.get("args");

    sqlFieldsQuery.setArgs(FormatSql.sqlValueToObject(sqlValueSeq1));
    logger.info("query EdgeBoxModel count sql  {}",sqlFieldsQuery);
    //数据总数
    //数据总数
    int totalCount = 0;

    try (FieldsQueryCursor<java.util.List<?>> cursor1 = cache.query(sqlFieldsQuery)) {

      for (java.util.List<?> row : cursor1) {
        totalCount = Integer.parseInt(row.get(0).toString());
      }

    }
    //分页工具
    Map<String, Object> page = PageUtil.page(limit, totalCount, offset);
    //起点数据
    int startIndex = (int) page.get("startIndex");
    //结点数据
    int endIndex = (int) page.get("endIndex");


    java.util.List<EdgeBoxModelEdge> modelList = new ArrayList<>();

    if (totalCount < 1) {

      //设置分页信息
      PageInfo pageInfo = PageInfo.newBuilder()
                                  .setHasNextPage((Boolean) page.get("hasNextPage"))
                                  .setHasPreviousPage((Boolean) page.get("hasPreviousPage"))
                                  .build();

      EdgeBoxModelFindAllReply reply = EdgeBoxModelFindAllReply.newBuilder()
                                                               .setReq(req)
                                                               .addAllEdges(modelList)
                                                               .setPageInfo(pageInfo)
                                                               .setTotalCount(0).build();

      return reply;
    }

    Iterator<Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel>> iterator = cursor.iterator();
    //计数器
    int times = 0;

    while (iterator.hasNext()) {

      Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel> p = iterator.next();
      if (p != null && !p.equals("")) {

        if (modelList.size() < limit) {
          if (times >= startIndex && times < endIndex) {
            EdgeBoxModelEdge modelEdge = EdgeBoxModelEdge.newBuilder()
                                                         .setCursor(p.getKey())
                                                         .setNode(EdgeBoxModel.newBuilder()
                                                                              .setId(p.getKey())
                                                                              .setName(p.getValue().getName())
                                                                              .setCreatedAt(TimestampToDate.dateTotimestamp(
                                                                                p.getValue().getCreatedAt()))
                                                                              .setUpdatedAt(TimestampToDate.dateTotimestamp(
                                                                                p.getValue().getUpdatedAt()))
                                                                              .setData(GetJObjectUtil.getData(p
                                                                                                                .getValue()
                                                                                                                .getData()))
                                                                              .setDesc(p.getValue().getDescription()))

                                                         .build();

            modelList.add(modelEdge);
          }

        } else {
          break;
        }
      }
      times++;

    }
    //设置分页信息
    PageInfo pageInfo = PageInfo.newBuilder()
                                .setHasNextPage((Boolean) page.get("hasNextPage"))
                                .setHasPreviousPage((Boolean) page.get("hasPreviousPage"))
                                .setStartCursor(page.get("startIndex").toString())
                                .setEndCursor(page.get("endIndex").toString()).build();

    return EdgeBoxModelFindAllReply.newBuilder()
                                   .setReq(req)
                                   .addAllEdges(modelList)
                                   .setPageInfo(pageInfo)
                                   .setTotalCount(totalCount).build();
  }


  EdgeBoxModelCreateOneReply createOneInner(EdgeBoxModelCreateOneRequest req) {
    //获取当前时间
    Timestamp createdAt = new Timestamp(System.currentTimeMillis());
    com.google.protobuf.Timestamp createdAt1 = Timestamps.fromMillis(new Date().getTime());
    Struct data = req.getData().getData();
    String data_str = GetJObjectUtil.getData(data);

    //存进新纪录
    String id = this.idGenerator.generate();
    cache.put(id,
              new com.eshipenet.shipnet.edgebox.EdgeBoxModel(req.getData().getName(),
                                                             req.getData().getDesc(),
                                                             createdAt,
                                                             createdAt,
                                                             data_str));

    EdgeBoxModel model = EdgeBoxModel
      .newBuilder()
      .setId(id)
      .setName(req.getData().getName())
      .setDesc(req.getData().getDesc())
      .setData(req.getData().getData())
      .setCreatedAt(createdAt1)
      .setUpdatedAt(createdAt1)
      .build();
    return EdgeBoxModelCreateOneReply.newBuilder().setData(model).setReq(req).build();
  }


  EdgeBoxModelUpdateOneReply updateOneInner(EdgeBoxModelUpdateOneRequest req) {

    //获取当前时间
    Timestamp updatedAt = new Timestamp(System.currentTimeMillis());

    //    Struct data = req.getData().getData();
    //    String data_str = GetJObjectUtil.getData(data);

    //查询指定数据
    SqlQuery<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel> sql =
      new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBoxModel.class, "id=?");

    QueryCursor<Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel>> cursor =
      cache.query(sql.setArgs(req.getData().getId()));
    logger.info("query EdgeBoxModel list by id sql  {}",sql);
    Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel> e = cursor.getAll().get(0);

    cache.put(req.getData().getId(),
              new com.eshipenet.shipnet.edgebox.EdgeBoxModel(req.getData().getName(),
                                                             e.getValue().getDescription(),
                                                             e.getValue().getCreatedAt(),
                                                             updatedAt,
                                                             e.getValue().getData()));

    com.google.protobuf.Timestamp updatedAt1 = Timestamps.fromMillis(new Date().getTime());

    EdgeBoxModel model = EdgeBoxModel
      .newBuilder()
      .setId(req.getData().getId())
      .setName(req.getData().getName())
      .setData(GetJObjectUtil.getData(e.getValue().getData()))
      .setDesc(e.getValue().getDescription())
      .setUpdatedAt(updatedAt1)
      .setCreatedAt((TimestampToDate.dateTotimestamp(e.getValue().getCreatedAt())))
      .build();
    return EdgeBoxModelUpdateOneReply.newBuilder().setData(model).setReq(req).build();
  }


  EdgeBoxModelDeleteOneReply deleteOneInner(EdgeBoxModelDeleteOneRequest req) {

    //查询指定数据
    SqlQuery<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel> sql =
      new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBoxModel.class, "id=?");

    QueryCursor<Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel>> cursor =
      cache.query(sql.setArgs(req.getId()));
    logger.info("query EdgeBoxModel list by id sql  {}",sql);
    Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBoxModel> e = cursor.getAll().get(0);

    com.google.protobuf.Timestamp updatedAt1 = Timestamps.fromMillis(new Date().getTime());

    EdgeBoxModel edgeBox = EdgeBoxModel
      .newBuilder()
      .setId(req.getId())
      .setName(e.getValue().getName())
      .setData(GetJObjectUtil.getData(e.getValue().getData()))
      .setUpdatedAt(updatedAt1)
      .setCreatedAt((TimestampToDate.dateTotimestamp(e.getValue().getCreatedAt())))
      .setDesc(e.getValue().getDescription())
      .build();

    SqlFieldsQuery query = new SqlFieldsQuery("delete from  EdgeBoxModel  where id=? ");
    cache.query(query.setArgs(req.getId())).getAll();
    logger.info("delete EdgeBoxModel  by id sql  {}",query);
    return EdgeBoxModelDeleteOneReply.newBuilder().setData(edgeBox).setReq(req).build();
  }

  /**
   * 根据id查询数据数量
   *
   * @param modelId
   * @return
   */
  int getModelCount(String modelId) {

    //查询数据总数
    SqlFieldsQuery query = new SqlFieldsQuery("select count(id) from  edgeboxmodel where id=? ");

    query.setArgs(modelId);
    logger.info("query EdgeBoxModel count by id sql  {}",query);
    //数据总数
    java.util.List<?> getCount = cache.query(query).getAll().get(0);

    Object obj = getCount.get(0);

    return Integer.parseInt(obj.toString());
  }


}
